package gclib.entities;

import com.bestcode.mathparser.IMathParser;
import com.bestcode.mathparser.MathParserFactory;
import gclib.LEVEL_SCALE;
import java.util.logging.Level;
import java.util.logging.Logger;

/**<b>melee examples:</b>
 * <ul>
 * <li>Melee weapon</li>
 * <li>Melee 1</li>
 * <li>Melee touch</li>
 * </ul>
 *
 *<b>range examples:</b>
 * <ul>
 * <li>Ranged weapon</li>
 * <li>Ranged [number]</li>
 * <li>Ranged sight</li>
 * </ul>
 *
 *<b>close examples:</b>
 * <ul>
 * <li>Close burst [number]</li>
 * <li>Close blast [number]</li>
 * </ul>
 *
 *<b>area examples:</b>
 * <ul>
 * <li>Area burst [number] within [number] squares</li>
 * <li>Area wall [number] within [number] squares</li>
 * </ul>
 *
 *<b>personal examples:</b>
 * <ul>
 * <li>Personal</li>
 * </ul>
 *
 * @author Jason
 */
public class AttackType {

    private LEVEL_SCALE levelScale = LEVEL_SCALE.NONE;
    private TYPE type;
    private Integer size;
    private Integer range;
    private ATTACK_TYPE attackType;
    private String valueScale;

    public static AttackType parse(String attackString) {
        return new AttackType();
    }

    public static AttackType parse(String attackString, LEVEL_SCALE levelScale) {

        return new AttackType();
    }

    /**
     * The most detailed AttackType generating parser. Based on the
     * attackString it will initialize the TYPE[, range][,size] of the
     * attack. This string must also contain a single '?'. Using the
     * valueScale and levelScale, it will be replaced. It will set the
     * leveling scale to be used during the various calculations.
     * @param attackString
     * @param levelScale
     * @param valueScale
     * @return an instantiated AttackType object.
     */
    public static AttackType parse(String attackString, LEVEL_SCALE levelScale, String valueScale) {
        AttackType anAttack = new AttackType();
        String[] tokens = attackString.split(" ");

        switch (tokens.length) {
            case 5:

            case 4:
            //no scenario
            case 3:
                if (tokens[2].equals("?")) {
                    anAttack.setSize(-1);
                } else {
                    anAttack.setSize(Integer.valueOf(tokens[2]));
                }
            case 2:
                anAttack.setAttackType(ATTACK_TYPE.valueOf(tokens[1].toUpperCase()));
            case 1:
                anAttack.setType(TYPE.valueOf(tokens[0].toUpperCase()));
        }
        anAttack.setLevelScale(levelScale);
        anAttack.setValueScale(valueScale);
        return anAttack;
    }

    public String getValueScale() {
        return valueScale;
    }

    public void setValueScale(String valueScale) {
        this.valueScale = valueScale;
    }

    public ATTACK_TYPE getAttackType() {
        return attackType;
    }

    public String getAttackTypeText() {
        return attackType.name().toLowerCase();
    }

    public void setAttackType(ATTACK_TYPE attackType) {
        this.attackType = attackType;
    }

    public Integer getRange() {
        return range;
    }

    public void setRange(Integer range) {
        this.range = range;
    }

    public Integer getSize() {
        return size;
    }

    public void setSize(Integer size) {
        this.size = size;
    }

    public TYPE getType() {
        return type;
    }

    public String getTypeText() {
        switch (type) {
            case AREA:
                return "Area";
            case CLOSE:
                return "Close";
            case MELEE:
                return "Melee";
            case PERSONAL:
                return "Personal";
            case RANGED:
                return "Ranged";
            default:
                return "";
        }
    }

    public void setType(TYPE type) {
        this.type = type;
    }

    public LEVEL_SCALE getLevelScale() {
        return levelScale;
    }

    public void setLevelScale(LEVEL_SCALE levelScale) {
        this.levelScale = levelScale;
    }

    public String getText(Integer characterLevel) {
        int calcSize = 0;
        if (size != null && size == -1) {
            calcSize = calculateValue(characterLevel);
        }
        if (range != null && range == -1) {
            calcSize = calculateValue(characterLevel);
        }
        return getTypeText() + " " + getAttackTypeText() + " " + (size == null ? "" : size == -1 ? calcSize : size) + (range == null ? "" : " within " + (range == -1 ? calcSize : range));
    }

    private Integer calculateValue(Integer characterLevel) {
        IMathParser mParser = MathParserFactory.create();
        try {
            mParser.createVar("x", ((characterLevel - 1) / levelScale.getPerLevel()) + 1);
        } catch (Exception ex) {
            Logger.getLogger(AttackType.class.getName()).log(Level.SEVERE, null, ex);
            return -1;
        }


        System.out.println("levelScale" + levelScale.getPerLevel());
        try {
            System.out.println("x=" + mParser.getVariable("x"));
            mParser.setExpression(valueScale);
        } catch (Exception ex) {
            Logger.getLogger(AttackType.class.getName()).log(Level.SEVERE, null, ex);
            return -1;
        }
        System.out.println("parsing " + valueScale);
        try {
            Object result = mParser.evaluate();
            return Double.valueOf(result.toString()).intValue();
        } catch (Exception ex) {
            Logger.getLogger(AttackType.class.getName()).log(Level.SEVERE, null, ex);
        }
        //using some type of math expression parser library compute the string
        return -1;
    }

    //each have rules for targeting and range  PHB Ch. 9
    public static enum TYPE {

        MELEE, RANGED, CLOSE, AREA, PERSONAL;
    };

    public static enum ATTACK_TYPE {

        WEAPON, TOUCH, NUMERIC, SIGHT, BURST, BLAST, WALL
    };
}
